# 对DataFrame进行的操作
import re
import numpy as np
import pandas as pd
import matplotlib.pylab as plt
import Judge
# 绘制进度条
from tqdm import tqdm


# 参考文章
# https://blog.csdn.net/python2021_/article/details/121806255

# 不同的分类放到字典、列表里面去
# 根据矩阵中的一列数据使用groupby分割开，返回对应的字典和列表
def DIV_DataFrame(datainput: pd.DataFrame, culumnsName: str = '要分割的列'):
    """
    例如：矩阵中有一列指标为年份,其中只有两个值，分别是'1997'和'1993'
    可以使用DIV_DataFrame(data,'年份'),来分割成1997年的数据矩阵和1993年的数据矩阵
    :param datainput: 矩阵数据输入
    :param culumnsName: 不同数据值分割的列
    :return: 返回数据
    返回变量1:datadict:不同数据的矩阵字典，在上面的案例中可以使用datadict['1997']来访问年份为1997年的矩阵
    相应的访问1993年的矩阵使用datadict['1993']来访问年份为1997年的矩阵
    返回变量2:datalist:不同数据的列表矩阵,相比较于上面的字典,没有key来访问,只有默认的排序顺序
    """
    grouped = datainput.groupby(culumnsName)
    datadict = {}
    datalist = []
    for key, item in grouped:
        datadict[key] = item
        datalist.append(item)
    return datadict, datalist


# 使用正则表达式将一列中的字符串分割
def DIV_Str(datainput: pd.DataFrame,
            culmnsName: str = '要分割的列',
            re_expr: str = '正则表达式',
            Is_Time_Sequence=False,
            re_expr_timesequence='[^\s]+'):
    """
    1、使用正则表达式将一列中的字符串分割
    2、这里的列是Series或着array，而不是根据这个直接分割矩阵！！！
    :param datainput:数据的数据矩阵
    :param culmnsName:需要分割的列的列名
    :param re_expr:正则表达式
    :param Is_Time_Sequence:是否是时间序列，如果是将采用时间序列的正则表达式
    :param re_expr_timesequence:时间序列的默认正则表达式'[^\s]+'
    :return:
    re_results：正则表达式索引的结果
    datainput：添加时间分割处理到源输入数据的结果，返回时最好使用原数据接受一下，防止丢失
    """
    # 这里的是array
    target = datainput[culmnsName].astype(str)
    v = target.values
    re_results = []
    if Is_Time_Sequence:
        re_expr = re_expr_timesequence
    R = []
    for i in range(len(v)):
        # ['2013-11-14', '10:00:00']
        result = re.findall(re_expr, v[i])
        if Is_Time_Sequence:
            # 分割每一种时间单位
            # ['2013', '11', '14']
            # ['10', '00', '00']
            re_Get = []
            for s in result:
                s_result = re.findall('[\d]+', s)
                re_Get.append(s_result)
            re_div = np.array(re_Get).flatten()
            re_div = re_div.astype(int)
            R.append(re_div)
        re_results.append(result)
    re_results = np.array(re_results)
    R = pd.DataFrame(R)
    R.columns = ['年份', '月份', '日期', '小时', '分钟', '秒']
    R.astype(int)
    # print(R)
    if Is_Time_Sequence:
        # print(R)
        # 自动添加日期列和具体时间列到原始数据
        # datainput
        datainput['年份日期'] = re_results[:, 0]
        datainput['具体时间'] = re_results[:, 1]
        datainput = pd.concat([datainput, R], axis=1, join='outer')
        # print('data:\n',datainput)

    return re_results, datainput


# 根据含有的字符提取多个DataFrame
# 用于查找行
def Get_DataFrames(
        data:pd.DataFrame,
        Find_columns='要匹配的列,如果匹配的是index则不用填',
        re_expr='正则匹配表达式'):
    """
    1、根据某一列的数据的不同类型，来提取矩阵DataFrame
    2、Find_columns,要找的列名，如果不填的话，则从行索引index当作依据来提取矩阵来提取DataFrame
    :param data: 输入数据DataFrame
    :param Find_columns: Find_columns,要找的列名
    :param re_expr: 正则表达式
    :return:
    ALL_Result：所有找到的行的Seies结果,为[Series1,Series2,....]的结构
    df:将ALL_Result合成为DataFrame矩阵的结果
    """
    Target = 1
    ALL_Result = []
    # 提取标识列
    if Find_columns == '要匹配的列,如果匹配的是index则不用填':
        # 匹配的是index列
        Target = data.index.values
    else:
        # 匹配的是其中的一列数据
        Target = data[Find_columns].values

    for i in range(len(Target)):
        result = re.findall(re_expr, Target[i])
        # 匹配到对应的字符串
        if result:
            ALL_Result.append(data.iloc[i, :])
    # 整合的结果
    # ALL_Result：所有的Seies结果
    # df:合成为矩阵的结果
    df = pd.DataFrame(ALL_Result)
    return ALL_Result, df


# 同时对数据进行多个正则表达式筛选,并制图、统计
# 每行每行进行循环，正则表达式也是
def Get_DataFrames_muti(
        data: pd.DataFrame,
        Find_columns: str = '要匹配的列,如果匹配的是index则不用填',
        re_exprs: [str] = '正则表达式列表',
        titles: [str] = '请输入标题列表',
):
    # 保存所有结果
    MutiResults = []
    MutiDataFrame = []

    for i in range(len(re_exprs)):
        # 对每个正则表达式求结果
        ALL_Result, df = Get_DataFrames(data, Find_columns, re_exprs[i])
        MutiResults.append(ALL_Result)
        MutiDataFrame.append(df)
    # 统计信息
    Statistics(MutiDataFrame, titles)
    # 绘制图
    Multi_Draw(MutiDataFrame, titles)
    # 返回所有结果
    return MutiResults, MutiDataFrame


# 更新异常值
def Update_Exception(DataFrame):
    # mu = DataFrame.mean().values
    judge_Result = []
    for i in range(len(DataFrame)):
        results = []
        # 每行元素的判断结果
        Q1 = DataFrame.iloc[i, :].quantile(0.25)
        Q3 = DataFrame.iloc[i, :].quantile(0.75)
        IQR = Q3 - Q1
        # CON1 = Q1 - 10 * IQR
        CON2 = Q3 + 30 * IQR
        CON3 = 20 * DataFrame.iloc[i, :].mean()
        for j in range(len(DataFrame.iloc[i, :])):
            # R1=DataFrame.iloc[i, j] < CON1
            R2 = DataFrame.iloc[i, j] > CON2
            R3 = DataFrame.iloc[i, j] > CON3
            R = R2 or R3
            # 填充值
            if R:
                print('检测到值异常:      ' + str(DataFrame.index.values[i]) + '<------->' + str(DataFrame.columns.values[j]))
                DataFrame.iloc[i, j] = np.mean(DataFrame.iloc[i, :])
            results.append(R)
        # 填充
        judge_Result.append(results)
    return judge_Result





# 设置其中一列时间数据为行索引
def Set_TimeIndex(data_df, col_name, drop=True):
    """
    设置其中一列时间数据为行索引
    :param data_df: 输入数据DataFrame
    :param col_name: 要设置为时间序列作为行index的列
    :param drop: 设置后是否删除掉这一列
    :return:
    """
    datatimes = pd.to_datetime(data_df[col_name])
    data_df.index = datatimes
    # 设置后删除原数据列
    if drop:
        data_df.drop(col_name, axis=1)
    return data_df
